﻿// -------------------------------------------------------------------------
//    @FileName         :    NFTransGetRole.cpp
//    @Author           :    gaoyi
//    @Date             :    24-8-28
//    @Email            :    445267987@qq.com
//    @Module           :    NFTransGetRole
//
// -------------------------------------------------------------------------

#include "NFTransGetRole.h"

#include <NFEventDisp.h>
#include <NFPlayer.h>
#include <NFPlayerMgr.h>
#include <NFPlayerPacketSendUtil.h>
#include <NFPlayerUtil.h>
#include <NFServiceMisc.h>
#include <NFSession.h>
#include <NFServerComm/NFServerCommon/NFIServerMessageModule.h>

#include "NFMirrorService.h"
#include "NFPacketSendUtil.h"
#include "NFTransInsertRole.h"
#include "NFTransLoadRole.h"
#include "proto_access2zone.nanopb.h"
#include "proto_cs_cmd.nanopb.h"
#include "proto_svr_common.nanopb.h"
#include "proto_svr_onlinesvr.pb.h"
#include "ZoneMergeDescEx.h"

NFTransGetRole::NFTransGetRole()
{
    if (EN_OBJ_MODE_INIT == NFShmMgr::Instance()->GetCreateMode())
    {
        CreateInit();
    }
    else
    {
        ResumeInit();
    }
}

NFTransGetRole::~NFTransGetRole()
{
}

int NFTransGetRole::CreateInit()
{
    SetState(TRANS_GETROLE_STATE_INIT);
    m_iServerType = NF_ST_LOGIC_SERVER;
    m_iTableId = E_TABLE_ROLE_DETAIL;
    m_loginLockId = 0;
    m_zoneId = 0;
    m_uin = 0;
    m_targetSvrId = 0;
    m_iMirrorSessionId = 0;
    return 0;
}

int NFTransGetRole::ResumeInit()
{
    return 0;
}

int NFTransGetRole::HandleCSMsgReq(const google::protobuf::Message* pMessage)
{
    const proto_ff::Proto_CSGetRoleReq* pCSMsgReq = dynamic_cast<const proto_ff::Proto_CSGetRoleReq*>(pMessage);
    CHECK_NULL(0, pCSMsgReq);
    int iRetCode = 0;
    uint64_t ullRoleId = pCSMsgReq->role_id();
    m_ullRoleId = ullRoleId;
    if (m_ullRoleId == 0)
    {
        iRetCode = ERR_CODE_ROLE_LOGIN_EMPTY;
        LOG_ERR(m_ullRoleId, iRetCode, "Proto_CSGetRoleReq roleId is 0, TransInfo:{}", DebugString());
        return iRetCode;
    }

    CHECK_EXPR(GetState() == TRANS_GETROLE_STATE_INIT, -1, "TransInfo:{}", DebugString());
    NFSession* pSession = GetClientSession();
    CHECK_NULL(ullRoleId, pSession);
    m_zoneId = pSession->GetZoneID();
    m_uin = pSession->GetUIN();

    return ProGetRoleDetailReq();
}

int NFTransGetRole::HandleDispSvrRes(uint32_t nMsgId, const NFDataPackage& packet, uint32_t reqTransId, uint32_t rspTransId)
{
    int iRetCode = 0;
    if (nMsgId == E_ONLINE2ZONE_GETROLE_RES)
    {
        iRetCode = OnHandleGetRoleRes(nMsgId, packet, reqTransId, rspTransId);
        CHECK_ERR(m_ullRoleId, iRetCode, "OnHandleGetRoleRes Failed, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
    }
    else if (nMsgId == E_SS_ZONE_ROLE_MIRROR_SESSION)
    {
        iRetCode = OnHandleRoleMirrorSession(nMsgId, packet, reqTransId, rspTransId);
        CHECK_ERR(m_ullRoleId, iRetCode, "OnHandleRoleMirrorSession Failed, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
    }
    else if (nMsgId == E_ZONE2ACCESS_SETROUTING)
    {
        iRetCode = OnHandleSetRoutingRes(nMsgId, packet, reqTransId, rspTransId);
        CHECK_ERR(m_ullRoleId, iRetCode, "OnHandleSetRoutingRes Failed, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
    }
    else
    {
        CHECK_ERR(m_ullRoleId, -1, "Unknown MsgId:{} TransInfo:{}", nMsgId, DebugString());
    }

    return 0;
}

int NFTransGetRole::OnHandleGetRoleRes(uint32_t nMsgId, const NFDataPackage& packet, uint32_t reqTransId, uint32_t rspTransId)
{
    CHECK_PLAYER_EXPR(m_ullRoleId, GetState() == TRANS_GETROLE_GET_ROLE, ERR_CODE_SYSTEM_OBJSTATUS_INVALID, "Invalid State:{} TransInfo:{}", GetState(), DebugString());
    auto pConfig = FindModule<NFIConfigModule>()->GetAppConfig(NF_ST_LOGIC_SERVER);
    CHECK_NULL(0, pConfig);

    proto_ff::Proto_Online2ZoneGetRoleRes res;
    CLIENT_MSG_PROCESS_WITH_PRINTF(packet, res);

    NFSession* pSession = GetClientSession();
    CHECK_PLAYER_EXPR(m_ullRoleId, pSession, -1, "ClientSession Failed, TransInfo:{}", DebugString());

    if (res.zone_id() != pSession->GetZoneID() || res.player_uin() != pSession->GetUIN() || res.role_id() != m_ullRoleId)
    {
        CHECK_PLAYER_EXPR(m_ullRoleId, false, -1, "GetRole Res Data Invalid, zoneId:{} != {}, uin:{} != {}, roleId:{} != {}, TransInfo:{}", res.zone_id(), pSession->GetZoneID(), res.player_uin(), pSession->GetUIN(), res.role_id(), m_ullRoleId, DebugString());
    }

    if (res.result() != 0)
    {
        LOG_ERR(m_ullRoleId, res.result(), "GetRole Failed, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
        return res.result();
    }

    m_loginLockId = res.login_lock_id();

    int iRetCode = 0;
    auto pPlayer = NFPlayerUtil::GetPlayerByRoleID(m_ullRoleId);
    if (pPlayer && res.active_logic_svr_id() > 0 && res.active_logic_svr_id() != pConfig->GetBusId())
    {
        iRetCode = ERR_CODE_ROLE_CHANGSVR;
        if (pPlayer->GetPlayerStatus() == CACHE_STATUS_LOGOUT)
        {
            iRetCode = ERR_CODE_PLAYER_LOGOUT;
        }

        if (pPlayer->GetPlayerStatus() == CACHE_STATUS_DELETE)
        {
            LOG_WARN(m_ullRoleId, iRetCode, "Online Logic {}, But This Logic {}, Has Player, {}", NFServerIDUtil::GetBusNameFromBusID(res.active_logic_svr_id()), NFServerIDUtil::GetBusNameFromBusID(pConfig->GetBusId()), DebugString());
        }
        else
        {
            LOG_ERR(m_ullRoleId, iRetCode, "Online Logic {}, But This Logic {}, Has Player, {}", NFServerIDUtil::GetBusNameFromBusID(res.active_logic_svr_id()), NFServerIDUtil::GetBusNameFromBusID(pConfig->GetBusId()), DebugString());
        }

        return iRetCode;
    }

    m_stRoleOne.FromPb(res.role());
    m_stStorageData.FromPb(res.storage_data());

    if (pPlayer == nullptr)
    {
        if (res.active_logic_svr_id() > 0 && res.active_logic_svr_id() != pConfig->GetBusId())
        {
            LOG_INFO(m_ullRoleId, "Player Online in another server {} / {}, {}", NFServerIDUtil::GetBusNameFromBusID(res.active_logic_svr_id()), NFServerIDUtil::GetBusNameFromBusID(pConfig->GetBusId()), DebugString());
            m_targetSvrId = res.active_logic_svr_id();
            iRetCode = NFMirrorService::MirrorSession(pSession, m_ullRoleId, m_targetSvrId, GetGlobalId());
        }
        else if (pConfig->IsCrossServer())
        {
            CHECK_ERR(m_ullRoleId, ERR_CODE_CROSSSVR_NO_PLAYER, "Cross Svr Not Exist Player, RoleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
            return ERR_CODE_CROSSSVR_NO_PLAYER;
        }
        else
        {
            GetCacheDataSingleReq<NFTransLoadRole>(m_ullRoleId, 0);
            SetState(TRANS_GETROLE_GETING_ROLEDETAIL);
        }
    }
    else
    {
        NFPlayerUtil::RestorePlayer(pPlayer, pSession);
        iRetCode = OnGetRoleSuccess(pPlayer, true);
        CHECK_ERR(m_ullRoleId, iRetCode, "OnGetRoleSuccess Failed, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
        return 0;
    }

    return 0;
}

int NFTransGetRole::ProGetRoleDetailReq()
{
    proto_ff::Proto_Zone2OnlineGetRoleReq req;
    req.set_zone_id(m_zoneId);
    req.set_player_uin(m_uin);
    req.set_role_id(m_ullRoleId);
    FindModule<NFIServerMessageModule>()->SendTransToOnlineServer(NF_ST_LOGIC_SERVER, ZoneMergeDescEx::Instance()->GetMergeZoneId(m_zoneId), E_ZONE2ONLINE_GETROLE_REQ, req, m_ullRoleId, GetGlobalId(), 0);
    SetState(TRANS_GETROLE_GET_ROLE);

    return 0;
}

int NFTransGetRole::InsertCacheDataRes(int ullId, int iTableId, int iReason, int32_t errCode, google::protobuf::Message* pMessage)
{
    return ProInsertRoleDetailRes(errCode, pMessage);
}

int NFTransGetRole::GetCacheDataRes(int ullId, int iTableId, int iReason, int32_t errCode, google::protobuf::Message* pMessage)
{
    return ProGetRoleDetailRes(errCode, pMessage);
}

int NFTransGetRole::ProGetRoleDetailRes(int32_t err_code, google::protobuf::Message* pMessage)
{
    CHECK_PLAYER_EXPR(m_ullRoleId, GetState() == TRANS_GETROLE_GETING_ROLEDETAIL, proto_ff::ERR_CODE_SYSTEM_OBJSTATUS_INVALID, "RoleId:{} Invalid State:{} TransInfo:{}", m_ullRoleId, GetState(), DebugString());

    NFSession* pSession = GetClientSession();
    CHECK_PLAYER_EXPR(m_ullRoleId, pSession, -1, "ClientSession Failed, TransInfo:{}", DebugString());

    int iRetCode = 0;

    if (err_code == ERR_CODE_STORESVR_ERRCODE_SELECT_EMPTY)
    {
        auto pPlayer = NFPlayerUtil::GetPlayerByRoleID(m_ullRoleId);
        if (pPlayer)
        {
            CHECK_ERR(m_ullRoleId, -1, "Role Already Exist, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
        }

        pPlayer = NFPlayerMgr::Instance()->CreatePlayer(m_ullRoleId);
        CHECK_NULL_WF(m_ullRoleId, pPlayer, "Create Player Failed! roleId:{}", m_ullRoleId);

        proto_ff::tbRoleDetail tbRoleDetailData;
        tbRoleDetailData.set_role_id(m_ullRoleId);
        iRetCode = pPlayer->InitConfig(&tbRoleDetailData, m_stRoleOne);
        CHECK_ERR(m_ullRoleId, iRetCode, "InitConfig Failed, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
        tbRoleDetailData.mutable_role_base_data()->mutable_base()->set_world_id(m_zoneId);
        tbRoleDetailData.mutable_role_base_data()->mutable_base()->set_uin(m_uin);

        iRetCode = InsertCacheDataReq<NFTransInsertRole>(m_ullRoleId, 0, tbRoleDetailData);
        CHECK_ERR(m_ullRoleId, iRetCode, "InsertCacheDataReq Failed, TransInfo:{}", DebugString());

        NFPlayerMgr::Instance()->DeletePlayer(pPlayer);

        SetState(TRANS_GETROLE_INSERTING_ROLEDETAIL);
    }
    else if (err_code == 0)
    {
        proto_ff::tbRoleDetail* pRoleDetail = dynamic_cast<proto_ff::tbRoleDetail*>(pMessage);
        CHECK_NULL_WF(m_ullRoleId, pRoleDetail, "Get RoleDetail Pb Failed, roleId: {}, TransInfo:{}", m_ullRoleId, DebugString());
        iRetCode = GetRoleDetailRes(pRoleDetail);
        CHECK_ERR(m_ullRoleId, iRetCode, "AddRoleDetailRes Failed, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
    }
    else
    {
        LOG_ERR(m_ullRoleId, -1, "ProGetRoleDetailRes Failed, err_code:{}, TransInfo:{}", err_code, DebugString());
        return proto_ff::ERR_CODE_SYSTEM_DATABASE_ERROR;
    }


    return 0;
}

int NFTransGetRole::OnGetRoleSuccess(NFPlayer* pPlayer, bool iResume)
{
    CHECK_NULL(m_ullRoleId, pPlayer);

    SendLoginEndToOnline();

    NFSession* pSession = GetClientSession();
    CHECK_NULL(m_ullRoleId, pSession);

    NFServiceMisc::SetSecData(pPlayer, m_sSecData);

    pPlayer->BindClientSession(pSession);
    pSession->BindPlayer(pPlayer);

    if (pPlayer->GetCreateTime() == 0)
    {
        pPlayer->SetCreateTime(NF_ADJUST_TIMENOW());
        NFEventDisp::OnPlayerRegister(pPlayer);
        pPlayer->SetIsCreateLogin(true);
    }

    if (pPlayer->IsOpenID())
    {
        pPlayer->SetOpenID(pSession->GetOpenID());
    }

    NFEventDisp::OnGetPlayerSuccess(pPlayer);

    SetState(TRANS_GETROLE_FINI_OK);

    NFPlayerPacketSendUtil::NotifyGetRoleRsp(pPlayer, &m_stStorageData);

    NFPlayerUtil::LoginPlayer(pPlayer, iResume);

    SetFinished(0);
    return 0;
}

int NFTransGetRole::ProInsertRoleDetailRes(int32_t err_code, google::protobuf::Message* pMessage)
{
    CHECK_PLAYER_EXPR(m_ullRoleId, GetState() == TRANS_GETROLE_INSERTING_ROLEDETAIL, ERR_CODE_SYSTEM_OBJSTATUS_INVALID, "Invalid State:{} TransInfo:{}", GetState(), DebugString());

    CHECK_PLAYER_EXPR(m_ullRoleId, err_code == 0, ERR_CODE_SYSTEM_DATABASE_ERROR, "Insert RoleDetail Failed, TransInfo:{}", DebugString());

    NFSession* pSession = GetClientSession();
    CHECK_NULL_WF(m_ullRoleId, pSession, "RoleID:{} GetClientSession Failed! DebugInfo:{}", m_ullRoleId, DebugString());

    auto pRoleDetail = dynamic_cast<proto_ff::tbRoleDetail*>(pMessage);
    CHECK_NULL_WF(m_ullRoleId, pRoleDetail, "Get RoleDetail Pb Failed, roleId: {}, TransInfo:{}", m_ullRoleId, DebugString());

    int iRetCode = InsertRoleDetailRes(pRoleDetail);
    CHECK_ERR(m_ullRoleId, iRetCode, "InsertRoleDetailRes Failed, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());

    return 0;
}

int NFTransGetRole::SendLoginEndToOnline()
{
    proto_ff::Proto_Zone2OnlineLoginEndNtf ntf;
    ntf.set_zone_id(m_zoneId);
    ntf.set_player_uin(m_uin);
    ntf.set_role_id(m_ullRoleId);
    ntf.set_login_lock_id(m_loginLockId);
    FindModule<NFIServerMessageModule>()->SendTransToOnlineServer(NF_ST_LOGIC_SERVER, ZoneMergeDescEx::Instance()->GetMergeZoneId(m_zoneId), E_ZONE2ONLINE_LOGIN_END_NTF, ntf, m_ullRoleId, GetGlobalId(), 0);
    m_loginLockId = 0;
    return 0;
}

int NFTransGetRole::OnTransFinished(int iRunLogicRetCode)
{
    if (m_loginLockId > 0)
    {
        SendLoginEndToOnline();
    }

    if (iRunLogicRetCode != 0)
    {
        if (GetClientSession())
        {
            NFPacketSendUtil::SendErrToClient(GetClientSession(), proto_ff::E_CS_GETROLE_RSP, (proto_ff::Proto_CS_ErrorCode)iRunLogicRetCode);
        }
    }
    return 0;
}

int NFTransGetRole::GetRoleDetailRes(proto_ff::tbRoleDetail* pPbCache)
{
    CHECK_NULL(m_ullRoleId, pPbCache);
    int iRetCode = 0;
    auto pPlayer = NFPlayerUtil::GetPlayerByRoleID(m_ullRoleId);
    if (pPlayer)
    {
        CHECK_WARN(m_ullRoleId, ERR_CODE_PLAYER_EXIST, "Player Already Exist, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
    }

    pPlayer = NFPlayerMgr::Instance()->CreatePlayer(m_ullRoleId);
    CHECK_NULL_WF(m_ullRoleId, pPlayer, "Create Player Failed! roleId:{}", m_ullRoleId);
    iRetCode = pPlayer->LoadFromDB(pPbCache, m_stRoleOne);
    CHECK_ERR(m_ullRoleId, iRetCode, "Load Player From DB Failed! roleId:{}, retCode:{}", m_ullRoleId, iRetCode);

    iRetCode = OnGetRoleSuccess(pPlayer, false);
    CHECK_ERR(m_ullRoleId, iRetCode, "OnGetRoleSuccess Failed, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());

    return 0;
}


int NFTransGetRole::InsertRoleDetailRes(proto_ff::tbRoleDetail* pPbCache)
{
    CHECK_NULL(m_ullRoleId, pPbCache);
    int iRetCode = 0;
    auto pPlayer = NFPlayerUtil::GetPlayerByRoleID(m_ullRoleId);
    if (pPlayer)
    {
        CHECK_ERR(m_ullRoleId, ERR_CODE_PLAYER_EXIST, "Player Already Exist, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
    }

    pPlayer = NFPlayerMgr::Instance()->CreatePlayer(m_ullRoleId);
    CHECK_NULL_WF(m_ullRoleId, pPlayer, "Create Player Failed! roleId:{}", m_ullRoleId);

    iRetCode = pPlayer->LoadFromDB(pPbCache, m_stRoleOne);
    CHECK_ERR(m_ullRoleId, iRetCode, "Load Player From DB Failed! roleId:{}, retCode:{}", m_ullRoleId, iRetCode);

    iRetCode = OnGetRoleSuccess(pPlayer, false);
    CHECK_ERR(m_ullRoleId, iRetCode, "OnGetRoleSuccess Failed, roleId:{}, TransInfo:{}", m_ullRoleId, DebugString());
    return 0;
}

int NFTransGetRole::OnHandleRoleMirrorSession(uint32_t nMsgId, const NFDataPackage& packet, uint32_t reqTransId, uint32_t rspTransId)
{
    proto_ff::Proto_SSZoneMirrorSessionRsp rsp;
    CLIENT_MSG_PROCESS_WITH_PRINTF(packet, rsp);

    NFSession* pSession = GetClientSession();
    CHECK_NULL_WF(m_ullRoleId, pSession, "RoleID:{} GetClientSession Failed! DebugInfo:{}", m_ullRoleId, DebugString());

    m_iMirrorSessionId = rsp.session_id();

    proto_ff::Zone2AccessSetRouting req;
    req.set_m_sessionobjid(m_iMirrorSessionId);
    req.set_m_targetsvrid(packet.nSrcId);
    req.set_m_transid(GetGlobalId());
    FindModule<NFIServerMessageModule>()->SendMsgToProxyServer(NF_ST_LOGIC_SERVER, pSession->GetConnBusId(), E_ZONE2ACCESS_SETROUTING, req, pSession->GetConnIndex(), pSession->GetGlobalId());

    pSession->SetSessionState(SESSION_STATE_TRANSFER, m_iMirrorSessionId, packet.nSrcId);

    LOG_INFO(m_ullRoleId, "RoleID:{} Mirror Session Success, sessionId:{} from {}", m_ullRoleId, m_iMirrorSessionId, NFServerIDUtil::GetBusNameFromBusID(packet.nSrcId));
    return 0;
}

int NFTransGetRole::OnHandleSetRoutingRes(uint32_t nMsgId, const NFDataPackage& packet, uint32_t reqTransId, uint32_t rspTransId)
{
    proto_ff::AccessZone2SetRouting rsp;
    CLIENT_MSG_PROCESS_WITH_PRINTF(packet, rsp);

    NFSession* pSession = GetClientSession();
    CHECK_NULL_WF(m_ullRoleId, pSession, "RoleID:{} GetClientSession Failed! DebugInfo:{}", m_ullRoleId, DebugString());

    pSession->SetWillDelete();

    CHECK_WARN(m_ullRoleId, rsp.result(), "Set Routing Failed, RoleID:{} Set Routing to iMirrorSessionId:{} iTargetSvr:{} recv Rsp", m_ullRoleId, m_iMirrorSessionId, NFServerIDUtil::GetBusNameFromBusID(m_targetSvrId));

    LOG_INFO(m_ullRoleId, "RoleID:{} Set Routing Success, Set Routing to iMirrorSessionId:{} iTargetSvr:{} recv Rsp", m_ullRoleId, m_iMirrorSessionId, NFServerIDUtil::GetBusNameFromBusID(m_targetSvrId));
    SetFinished(0);

    proto_ff::Proto_SSZoneMirrorLogin req;
    req.set_session_id(m_iMirrorSessionId);
    req.set_role_id(m_ullRoleId);

    FindModule<NFIServerMessageModule>()->SendMsgToLogicServer(NF_ST_LOGIC_SERVER, m_targetSvrId, E_SS_ZONE_ROLE_MIRROR_LOGIN, req, m_ullRoleId);
    return 0;
}
